package com.ssm.juc.thread;


import java.util.concurrent.*;

public class DelayQueueManager {

    private static DelayQueueManager instance = new DelayQueueManager();
    public static DelayQueueManager getInstance() {
        return instance;
    }

    private DelayQueue<DelayMessage<Object>> delayQueue = new DelayQueue<>();
    private ExecutorService executorService;

    private DelayQueueManager() {
        executorService = Executors.newSingleThreadExecutor();
        executorService.execute(new Thread(this::executeThread));
    }

    public static void main(String[] args) {
        DelayQueueManager delayQueueManager = DelayQueueManager.getInstance();
        System.out.println("start " + System.currentTimeMillis());
        delayQueueManager.put(new DelayMessage<>(5000L, "Hello Tom"));
        delayQueueManager.put(new DelayMessage<>(8000L, "Hello Ktm"));
        delayQueueManager.put(new DelayMessage<>(2000L, "Hello Star"));
    }

    /**
     * 加入到延时队列中
     *
     * @param task
     */
    public void put(DelayMessage<Object> task) {
        System.out.println("加入延时任务 delay= " + task.getDelay(TimeUnit.MILLISECONDS) + "ms");
        delayQueue.put(task);
    }

    /**
     * 延时任务执行线程
     */
    private void executeThread() {
        while (true) {
            DelayMessage<Object> task = null;
            try {
                task = delayQueue.take();
                processTask(task);
            } catch (Exception e) {
                System.err.println("延时任务执行失败 task:" + task + " err:" + e);
            }
        }
    }

    /**
     * 内部执行延时任务
     *
     * @param task
     */
    private void processTask(DelayMessage<Object> task) {
        if (task == null) {
            return;
        }
        Object data = task.getData();
        System.out.println("out:" + data + " run time:" + System.currentTimeMillis());
    }


    static class DelayMessage<T> implements Delayed {
        /**
         * 到期时间 单位：ms
         */
        private long activeTime;
        /**
         * 业务实体
         */
        private T data;

        public DelayMessage(long activeTime, T data) {
            // 将传入的时间转换为超时的时刻
            this.activeTime = TimeUnit.NANOSECONDS.convert(activeTime, TimeUnit.MILLISECONDS)
                    + System.nanoTime();
            this.data = data;
        }

        public long getActiveTime() {
            return activeTime;
        }

        public T getData() {
            return data;
        }

        /**
         * 按照剩余时间进行排序
         *
         * @param o
         * @return
         */
        @Override
        public int compareTo(Delayed o) {
            // 订单剩余时间-当前传入的时间= 实际剩余时间（单位纳秒）
            long d = getDelay(TimeUnit.NANOSECONDS) - o.getDelay(TimeUnit.NANOSECONDS);
            // 根据剩余时间判断等于0 返回1 不等于0
            // 有可能大于0 有可能小于0  大于0返回1  小于返回-1
            return (d == 0) ? 0 : ((d > 0) ? 1 : -1);
        }

        /**
         * 获取剩余时间
         *
         * @param unit
         * @return
         */
        @Override
        public long getDelay(TimeUnit unit) {
            // 剩余时间= 到期时间-当前系统时间，系统一般是纳秒级的，所以这里做一次转换
            return unit.convert(activeTime - System.nanoTime(), TimeUnit.NANOSECONDS);
        }
    }


}
